#! /usr/bin/env seed

Gio = imports.gi.Gio;
JSON = imports.JSON;
var Gravy = imports.gravy.Gravy;

var log_msg = Seed.print;

var results = {
    text: '',
    passed: 0,
    errors: 0,
    failed: 0
};

function assert (test) {
    if (test) {
        return;
    } else {
        throw {name: 'TestAssertionFailure'};
    }
}

function print_dom(node, indent) {
    if (indent === undefined) {
        indent = '';
    }
    var desc = indent + node.type;
    if (node.type == 'text') {
        desc += ': "' + node.text + '"';
    } else if (node.type == 'header') {
        desc += ' level ' + String(node.level);
    } else if (node.type == 'extension call') {
        var args = node['args'].join(', ');
        for (name in node['named args']) {
            if (args == '') {
                args = name + ' = "' + node['named args'][name] + '"';
            } else {
                args += ', ' + name + ' = "' + node['named args'][name] + '"';
            }
        }
        desc += '(' + args + ')';
    }
    log_msg(desc.replace(/\n/, '\\n'));
    if (node.children) {
        for (var i = 0; i < node.children.length; ++i) {
            print_dom(node.children[i], '    ' + indent);
        }
    }
}

function compare_dom(dom, expected) {
    assert(dom.type == expected.type);
    for (name in expected) {
        if (name == 'children') {
            continue;
        } else if (typeof(expected[name]) == 'object') {
            for (var child in expected[name]) {
                assert(dom[name][child] == expected[name][child]);
            }
        } else {
            assert(dom[name] == expected[name]);
        }
    }
    if (! expected.children) {
        assert((! dom.children) || (dom.children.length == 0));
    } else {
        assert(dom.children && dom.children.length == expected.children.length);
        for (var i = 0; i < expected.children.length; ++i) {
            compare_dom(dom.children[i], expected.children[i]);
        }
    }
}

function compare_parse(text, expected) {
    log_msg('Gravy Input:');
    log_msg(text);
    var tokenizer = new Gravy.Tokenizer();
    var parser = new Gravy.Parser(new Gravy.GravyDomGenerator);
    // Set the testing flag
    parser._testing = true;
    var dom = parser.parse(tokenizer.tokenize(text));
    log_msg('DOM Output:');
    print_dom(dom);
    compare_dom(dom, expected);
}

function run_test (fname, name, test) {
    var output = '';
    log_msg = function (text) {
        output = output + text + '\n';
    }

    try {
        compare_parse(test['text'], test['dom']);
        results.text += '.';
        results.passed++;
    } catch (e) {
        if (e.name == 'TestAssertionFailure') {
            results.text += 'F';
            results.failed++;
            Seed.print('Test \"' + name + '" in "' + fname + '" failed!');
            Seed.print('Output from test follows:');
            Seed.print('------------------------------------------------');
            Seed.print(output +
                '------------------------------------------------\n');
        } else {
            results.text += 'E';
            results.errors++;
            Seed.print('Error in test "' + name + '" in "' + fname + '"');
            Seed.print(e.name + ': ' + e.message);
            Seed.print('Output from test follows:');
            Seed.print('------------------------------------------------');
            Seed.print(output +
                '------------------------------------------------\n');
        }
    }
}

function run_file_tests(fname, file) {
    var test_data = JSON.parse('{' + file.read().get_contents() + '}');
    for (var test in test_data) {
        run_test(fname, test, test_data[test]);
    }
}

function run_dir_tests(dir) {
    var enumerator = dir.enumerate_children('standard::name,standard::type');
    var finfo;
    while (finfo = enumerator.next_file()) {
        var ftype = finfo.get_file_type();
        var fname = finfo.get_name();
        if (fname.match(/^test[_-]/)) {
            if (ftype == 2) {
                run_dir_tests(dir.get_child(fname));
            } else if (ftype == 1) {
                run_file_tests(fname, dir.get_child(fname));
            }
        }
    }
}

// Find the tests directory
var path = imports.searchPath[imports.searchPath.length - 2];
if (! path.match(/gravy-js\/?$/)) {
    path = '.';
}
var dir = Gio.file_new_for_path(path);
dir = dir.get_parent();
dir = dir.get_child('tests');

// Run the tests
run_dir_tests(dir);
Seed.print(results.text);
Seed.print(String(results.passed) + ' Passed, ' + String(results.failed) +
        ' Failed, and ' + String(results.errors) + ' Errors');

